package com.ljx.templateMode;

/**
 * 模板方法
 * 模板方法设计模式是行为型设计模式中的一种，用在一个功能的完成需要经过一系列步骤，这些步骤是固定的，
 * 但是中间某些步骤具体行为是待定的，在不同的场景中行为不同，此时就可以考虑使用模板方法设计模式来完成，不同的场景对应不同的子类实现
 *
 * 优点：
 * 它封装了不变部分，扩展可变部分。它把认为是不变部分的算法封装到父类中实现，而把可变部分算法由子类继承实现，便于子类继续扩展。
 * 它在父类中提取了公共的部分代码，便于代码复用。
 * 部分方法是由子类实现的，因此子类可以通过扩展方式增加相应的功能，符合“开闭原则”。
 *
 * 缺点：
 * 对每个不同的实现都需要定义一个子类，这会导致类的个数增加，系统更加庞大，设计也更加抽象，间接地增加了系统实现的复杂度。
 * 父类中的抽象方法由子类实现，子类执行的结果会影响父类的结果，这导致一种反向的控制结构，它提高了代码阅读的难度。
 * 由于继承关系自身的缺点，如果父类添加新的抽象方法，则所有子类都要改一遍。
 *
 * 应用场景：
 * 算法的整体步骤很固定，但其中个别部分易变时，这时候可以使用模板方法模式，将容易变的部分抽象出来，供子类实现。
 * 当多个子类存在公共的行为时，可以将其提取出来并集中到一个公共父类中以避免代码重复。首先，要识别现有代码中的不同之处，
 * 并且将不同之处分离为新的操作。最后，用一个调用这些新的操作的模板方法来替换这些不同的代码。
 * 当需要控制子类的扩展时，模板方法只在特定点调用钩子操作，这样就只允许在这些点进行扩展。
 *
 *
 * 经典案例：
 * servletApi  HttpServlet
 * spring  AbstractController
 *
 * @作者 LJX
 * @日期 2022/12/21 15:21
 */
public class TemplateTest {

    public static void main(String[] args) {
        FatherClass sc1 = new SubClass1();
        sc1.skeletonFn();

        System.out.println("......................................");

        FatherClass sc2= new SubClass2();
        sc2.skeletonFn();
    }

}

/**
 * 父类 定义骨架算法
 */
abstract class FatherClass{

    /**
     * 骨架算法
     */
    public void skeletonFn(){
        System.out.println("步骤1...");
        System.out.println("步骤2...");
        System.out.println("步骤3...");
        templateFn();
    }

    /**
     * 模板方法（需要子类具体实现）
     */
    abstract protected void templateFn();

}

/**
 * 子类1
 */
class SubClass1 extends FatherClass{

    @Override
    protected void templateFn() {
        System.out.println("子类实现1");
    }
}

/**
 * 子类2
 */
class SubClass2 extends FatherClass{

    @Override
    protected void templateFn() {
        System.out.println("子类实现2");
    }
}
